Skip to content

test(e2e): W1 LIVE auth/login coverage (OAuth state-replay, logout-revocation, CLI device-flow, /auth/me, CORS)#172

Merged
mastermanas805 merged 1 commit into
mainfrom
w1-auth-live-e2e
Jun 4, 2026
Merged

test(e2e): W1 LIVE auth/login coverage (OAuth state-replay, logout-revocation, CLI device-flow, /auth/me, CORS)#172
mastermanas805 merged 1 commit into
mainfrom
w1-auth-live-e2e

Conversation

@mastermanas805

Copy link
Copy Markdown
Member

What

Implements W1 (P0) from docs/sessions/2026-06-04/USER-FLOW-INVENTORY-AND-TEST-MATRIX.md §W1 — the highest-priority auth block. The past prod-login outage (2026-05-29 → 30) was a UI↔backend auth-integration gap; this adds real-backend E2E for every leg of that surface as e2e/live-auth.spec.ts.

Built on the WS1-P1 LIVE harness (cohort.ts, cleanup-ledger.ts, reap-cohort.ts, playwright.live.config.ts, e2e-live.yml) and the W2 spec (live-anon-provision.spec.ts) — mirrors their E2E_LIVE=1 gating + ledger-before-assert + reap patterns.

Legs covered (matrix IDs)

Leg What it asserts
A4 GitHub OAuth start GET /auth/github/start → 3xx to github.com authorize w/ a single-use state param
A6 OAuth state-replay forged / never-issued state on the callback fails closed — no session_token minted, not a 200
A7 CORS (AUTH-004) OPTIONS /auth/exchangeACAC:true + ACAO:https://instanode.dev
A8 /auth/me valid bearer synthetic HS256 bearer → 200 + claimed email + tier='free'
A9 /auth/me bad bearer tampered signature → 401; correctly-signed-but-expired → 401
A10 logout revocation valid bearer 200 → POST /auth/logoutSAME bearer/jti → 401 (the precise incident class)
A12/A13 CLI device-flow POST /auth/cli auth_url host == canonical instanode.dev (parsed hostname, not the api host); pre-approval poll → status, no api_token
A1 magic-link start POST /auth/email/start → 2xx {ok:true}

Skip-annotated (NOT silently omitted)

  • Full magic-link callback flow is test.skip with an explicit reason: blocked on Brevo sender validation (operator action — validate noreply@instanode.dev; project_brevo_sender_not_validated.md). The emailed link can't be delivered until then, so start-leg only is exercised.

Mint path (Brevo-free)

Per TEST-ACCOUNTS-AND-NR-SYNTHETICS-PLAN.md §1.1: account legs provision an anon cache → /claim into a real user/team → mint an HS256 session JWT with E2E_JWT_SECRET (no email round-trip, no GitHub). Those legs self-skip loudly when E2E_JWT_SECRET is unset; the contract-only legs (OAuth state-replay, CORS, CLI canonical host, magic-link start, tampered token) still run. e2e-live.yml now passes optional E2E_JWT_SECRET.

Safety (rule 24)

Every minted resource is cohort-branded + ledgered before any throwing assertion + reaped inline / afterAll / out-of-process reap-cohort.ts. Named live-*.spec.ts so playwright.live.config.ts picks it up and the default mocked per-PR config ignores it — per-PR CI never needs a live backend (all 11 tests skip cleanly without E2E_LIVE=1).

Gate

npm run gate (tsc --noEmit && npm run build && vitest run) GREEN — 80 files, 1115 passed / 3 skipped; mocked suite unchanged.

🤖 Generated with Claude Code

…, /auth/me, CORS)

Adds e2e/live-auth.spec.ts — the W1 (P0) real-backend auth suite from
docs/sessions/2026-06-04/USER-FLOW-INVENTORY-AND-TEST-MATRIX.md §W1. Closes
the matrix gap whose failure surface caused the 2026-05-29→30 prod-login
outage (a UI↔backend auth-integration regression).

Legs covered (E2E_LIVE=1-gated; whole file skips loudly in per-PR CI so the
gate never depends on a live backend):
  - A4/A6 GitHub OAuth: start → github.com authorize w/ single-use state;
    forged/never-issued state callback must fail closed (no session_token).
  - A7  /auth/exchange CORS contract (ACAC:true + ACAO:https://instanode.dev) —
    the AUTH-004 surface.
  - A8/A9 /auth/me: valid synthetic bearer → 200 + claimed email + tier='free';
    tampered + expired bearers → 401.
  - A10 logout revocation (the precise incident class): valid bearer 200 →
    POST /auth/logout → SAME bearer/jti on /auth/me → 401.
  - A12/A13 CLI device-flow: POST /auth/cli auth_url host == canonical
    instanode.dev (parsed hostname, not the api host); pre-approval poll →
    status, no api_token.
  - A1 magic-link START leg → 2xx {ok:true}; the FULL callback flow is
    test.skip with an explicit "blocked on Brevo sender validation (operator)"
    annotation, NOT a silent omission.

Mint path is Brevo-free (TEST-ACCOUNTS-AND-NR-SYNTHETICS-PLAN.md §1.1):
account legs provision→/claim a real user/team then mint an HS256 session JWT
with E2E_JWT_SECRET; they self-skip loudly when the secret is unset while the
contract-only legs still run. Every minted resource is cohort-branded +
ledgered-before-assert + reaped inline / afterAll / reap-cohort.ts (rule 24).
Mirrors live-anon-provision + auth-roundtrip patterns; named live-*.spec.ts so
playwright.live.config.ts picks it up and the default mocked config ignores it.
Wires optional E2E_JWT_SECRET into e2e-live.yml.

npm run gate: GREEN (tsc --noEmit + build + vitest 1115 passed / 3 skipped,
80 files; mocked suite unchanged). live config lists 11 tests, all skip
cleanly without E2E_LIVE.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mastermanas805
mastermanas805 enabled auto-merge (squash) June 4, 2026 19:34
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown

size-limit report 📦

Path Size
dist/assets/index-902QtfQT.js 161.98 KB (0%)
dist/assets/index-BsJUZYRr.css 6.13 KB (0%)

@mastermanas805
mastermanas805 merged commit 16ae02d into main Jun 4, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant